// 拦截对象属性的读写，可以理解为门卫，代理
// Object.defineProperty  vue2.x vue1.x
// Proxy vue3.x
const person = {
  name: 'cuvee',
  age: 30
}

const personProxy = new Proxy(person /* target: 代理的目标对象 */, {
  get(target, prop) {
    // console.log(target, prop);
    // return 100;
    return prop in target ? target[prop] : 'default';
  }, /* get：代理目标对象获取属性的时候触发 */
  set(target, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('need a int!')
      }
    }
    target[prop] = value;
  }, /* set：代理目标对象设置属性的时候触发 */
  deleteProperty(target, prop) {

  }, /* deleteProperty: 代理目标对象属性的删除 */
  getPrototypeOf() {

  }, /* getPrototypeOf: 读取代理对象的原型时触发该操作 Object.getPrototypeOf(proxy) */
  setPrototypeOf() {

  }, /* setPrototypeOf: 设置代理对象的原型时触发该操作 Object.setPrototypeOf(proxy, null)*/
  isExtensible() {

  }, /* isExtensible: 判断一个对象是否是可扩展 Object.isExtensible(proxy) */
  preventExtensions() {

  }, /* 让一个代理对象不可扩展时触发该操作 Object.preventExtensions(proxy)*/
  getOwnPropertyDescriptor() {

  }, /* 在获取代理对象某个属性的属性描述符时触发该操作 Object.getOwnPropertyDescriptor(proxy, 'foo') */
  defineProperty() {

  }, /* 在定义代理对象某个属性时的属性描述时触发该操作 Object.defineProperty(proxy, 'foo', {}) */
  has() {

  }, /* 在判断某个对象是否拥有某个属性时触发该操作 'foo' in proxy */
  ownKeys() {

  }, /* 在获取代理对象的所有属性键时触发该操作 Object.getOwnPropertyNames(proxy) Object.getOwnPropertySymbols
      Object.keys()  for...in
  */
  apply() {
    // 拦截Proxy实例作为函数调用的操作  proxy()  proxy.call()  proxy.apply()
  }, /* 在调用一个目标对象为函数的代理对象时触发该操作  proxy() */
  constructor() {

  } /* 在给一个目标对象为构造函数的代理对象构造实例时触发操作  new proxy() */
}/* handler: 代理的处理对象 */)

personProxy.name;
personProxy.age = 20;


// Object.defineProperty只能监听属性的读写
// Proxy可以有更多的操作，例如删除属性

// 对于数组的监视
// Object.defineProperty只能重写数组原型上的方法
// Proxy可以直接监视
const list = [];
const listProxy = new Proxy(list, {
  set(target, prop, value) {
    console.log(target, prop, value);
    target[prop] = value; // 自动推演下标
    return true;  // 表示设置成功
  },
  get(target, prop) {
    // 这儿要注意，调用数组的方法的时候，会首先的触发get操作，因此这儿必须要返回一个函数，否则会包错误
    return target[prop];
  }
});
listProxy.push(1);
// Proxy是以非侵入式的方式监听对象
// Object.defineProperty需要对目标对象上的每个属性，都要显示的监视一次
